package service

import (
	"awesomeProject/app/model"
	"awesomeProject/app/response"
	"awesomeProject/global"
	"awesomeProject/util"
	uuid "github.com/satori/go.uuid"
	"strconv"
)

type CasbinSrv struct{}

var (
	roleSrv       RoleSrv
	permissionSrv PermissionSrv
	userSrv       UserSrv
	sEnforcer     util.SEnforcer
)

func (r *CasbinSrv) AddPermissionsForRole(rId uint, pIds []uint, operator model.User) response.Resp {
	role := roleSrv.FindByID(rId)
	if role.ID == 0 {
		return response.ErrRecordNotFound
	}
	permissions := permissionSrv.QueryByIds(pIds)
	var rules [][]string
	for _, val := range permissions {
		rules = append(rules, []string{strconv.Itoa(int(role.ID)), val.Uri, val.Method})
	}

	_, err := sEnforcer.RemoveFilteredPolicy(0, strconv.Itoa(int(role.ID)))
	if err != nil {
		return response.ErrDel.SetMsg(err.Error())
	}
	_, err = sEnforcer.AddPolicies(rules)
	if err != nil {
		return response.ErrStore.SetMsg(err.Error())
	}

	return response.OK
}

func (r *CasbinSrv) AddRolesForUser(uid uint, rIds []uint, operator model.User) response.Resp {
	user := userSrv.FindByID(uid, operator.CompanyId)
	var roleIds []string
	for _, val := range rIds {
		roleIds = append(roleIds, strconv.Itoa(int(val)))
	}
	_, err := sEnforcer.RemoveFilteredPolicy(0, user.UUID.String())
	if err != nil {
		return response.ErrDel.SetMsg(err.Error())
	}
	_, err = sEnforcer.DeleteRolesForUser(user.UUID.String())
	if err != nil {
		return response.ErrDel.SetMsg(err.Error())
	}
	_, err = sEnforcer.AddRolesForUser(user.UUID.String(), roleIds)
	if err != nil {
		return response.ErrDel.SetMsg(err.Error())
	}

	return response.OK
}

// Update 更新权限
func (r *CasbinSrv) Update(newUri, newMethod, oldUri, oldMethod string) error {
	return global.Gorm.Table("casbin_rule").Where("v1 = ? AND v2 = ?", oldUri, oldMethod).Updates(map[string]interface{}{
		"v1": newUri,
		"v2": newMethod,
	}).Error
}

func (r *CasbinSrv) UserRoles(uid uint, operator model.User) response.Resp {
	user := userSrv.FindByID(uid, operator.CompanyId)
	roleIdStrList, err := sEnforcer.GetRolesForUser(user.UUID.String())
	if err != nil {
		return response.ErrQuery
	}
	var roleIds []uint
	for _, roleId := range roleIdStrList {
		roleIdUint, _ := strconv.Atoi(roleId)
		roleIds = append(roleIds, uint(roleIdUint))
	}
	userRoles := roleSrv.QueryByIds(roleIds)
	rolesAll, err := roleSrv.AllWithChecked()
	if err != nil {
		return response.ErrQuery
	}

	var rolesWithChecked []model.RoleWithChecked
	for _, role := range rolesAll {
		var roleWithChecked model.RoleWithChecked
		if !operator.SuperAdmin && role.ID == 1 {
			continue
		}
		for _, uRole := range userRoles {
			if uRole.ID == role.ID {
				roleWithChecked.Checked = true
			}
		}
		roleWithChecked.Role = role
		rolesWithChecked = append(rolesWithChecked, roleWithChecked)
	}

	return response.OK.WithData(rolesWithChecked)
}

func (r *CasbinSrv) rolesHas(role model.Role, roles []model.Role) bool {
	for _, roleWithChecked := range roles {
		if roleWithChecked.ID == role.ID {
			return true
		}
	}
	return false
}

func (r *CasbinSrv) QueryUserRoleIds(uuid uuid.UUID) []model.CasbinModel {
	var rules []model.CasbinModel
	_ = global.Gorm.Where("v0=? and ptype='g'", uuid).Find(&rules).Error

	return rules
}
